Using the Game Effect System
1. Introduction
In game development, effects are crucial elements that enhance the visual experience. They can enrich the game's atmosphere, highlight key events, and provide instant visual feedback. This tutorial will introduce how to use the Effekseer effect system in the Dora SSR engine, as well as how to utilize the engine's built-in Particle system.
2. What is Effekseer?
Effekseer is a free, open-source effect editor that supports multiple platforms including Windows, macOS, and Linux. It allows artists and developers to create a variety of particle effects, such as explosions, flames, beams, and more. Effekseer supports multiple rendering modes and advanced features, such as:
- Particle Emission and Control: Supports emitting particles from various shapes such as points, lines, and surfaces, with fine control over the particle lifecycle.
- Rendering Features: Supports blending modes, texture mapping, lighting, and shadows.
- Multi-Platform Support: Can export effects to various game engines and platforms, including Dora SSR.
3. Using Effekseer
The Dora SSR engine has integrated the Effekseer effect system, allowing developers to directly load and play effect files generated by the Effekseer editor (typically with .efk
or .efkefc
extensions) in their games.
3.1 Using the EffekNode Class
In Dora SSR, the EffekNode
class can be used to manage the playback of Effekseer effects, acting as a scene node to manage properties like geometric position, rotation, and scale of the effects. Here are the main methods and usages of the EffekNode
class:
-
Creating an EffekNode Object
- Lua
- Teal
- TypeScript
- YueScript
local EffekNode <const> = require("EffekNode")
local effekNode = EffekNode()local EffekNode <const> = require("EffekNode")
local effekNode = EffekNode()import { EffekNode } from "Dora";
const effekNode = EffekNode();_ENV = Dora
effekNode = EffekNode! -
Playing Effects
- Lua
- Teal
- TypeScript
- YueScript
local handle = effekNode:play("Particle/effek/Laser01.efk", Vec2(100, 200), 0)
local handle = effekNode:play("Particle/effek/Laser01.efk", Vec2(100, 200), 0)
const handle = effekNode.play("Particle/effek/Laser01.efk", Vec2(100, 200), 0);
handle = effekNode\play "Particle/effek/Laser01.efk", Vec2(100, 200), 0
The
play
method accepts the following parameters:filename
: The path to the effect file.pos
(optional): The two-dimensional coordinates to play the effect, defaulting to(0, 0)
.z
(optional): The Z-axis coordinate to play the effect, defaulting to0
.
-
Stopping Effects
- Lua
- Teal
- TypeScript
- YueScript
effekNode:stop(handle)
effekNode:stop(handle)
effekNode.stop(handle);
effekNode\stop handle
handle
: The effect handle returned by theplay
method.
-
Listening for Effect End Events
- Lua
- Teal
- TypeScript
- YueScript
effekNode:onEffekEnd(function(handle)
print("Effect ended, handle: " .. handle)
end)effekNode:onEffekEnd(handle => {
print("Effect ended, handle: " .. handle)
})effekNode.onEffekEnd(handle => {
print("Effect ended, handle: " + handle);
});effekNode\onEffekEnd (handle) ->
print "Effect ended, handle: #{handle}"
3.2 Practical Example: Playing a Laser Effect
Here is a complete example demonstrating how to play a laser effect named Laser01.efk
in Dora SSR, along with callback handling when the effect ends.
- Lua
- Teal
- TypeScript
- YueScript
-- Import necessary modules
local EffekNode <const> = require("EffekNode")
local Vec2 <const> = require("Vec2")
-- Create an EffekNode object
local effekNode = EffekNode()
-- Set the overall 3D rotation angle of the effect node
effekNode.angleY = -90
-- Play the laser effect at coordinates (100, 200)
local laserHandle = effekNode:play("Particle/effek/Laser01.efk", Vec2(100, 200))
-- Register effect end callback
effekNode:onEffekEnd(function(handle)
if handle == laserHandle then
print("Laser effect ended")
end
end)
-- Import necessary modules
local EffekNode <const> = require("EffekNode")
local Vec2 <const> = require("Vec2")
-- Create an EffekNode object
local effekNode = EffekNode()
-- Set the overall 3D rotation angle of the effect node
effekNode.angleY = -90
-- Play the laser effect at coordinates (100, 200)
local laserHandle = effekNode:play("Particle/effek/Laser01.efk", Vec2(100, 200))
-- Register effect end callback
effekNode:onEffekEnd(function(handle: integer)
if handle == laserHandle then
print("Laser effect ended")
end
end)
// Import necessary modules
import { EffekNode } from "Dora";
// Create an EffekNode object
const effekNode = EffekNode();
// Set the overall 3D rotation angle of the effect node
effekNode.angleY = -90;
// Play the laser effect at coordinates (100, 200)
const laserHandle = effekNode.play("Particle/effek/Laser01.efk", Vec2(100, 200));
// Register effect end callback
effekNode.onEffekEnd(handle => {
if (handle === laserHandle) {
print("Laser effect ended");
}
});
-- Import necessary modules
_ENV = Dora
-- Create an EffekNode object
effekNode = EffekNode!
-- Set the overall 3D rotation angle of the effect node
effekNode.angleY = -90
-- Play the laser effect at coordinates (100, 200)
laserHandle = effekNode\play "Particle/effek/Laser01.efk", Vec2(100, 200)
-- Register effect end callback
effekNode\onEffekEnd (handle) ->
if handle == laserHandle
print "Laser effect ended"
3.3 Controlling the Playback and Stopping of Effects
Sometimes, we need to control the playback and stopping of effects based on game logic. For example, playing an effect when a player releases a skill and stopping the effect when the skill is interrupted.
- Lua
- Teal
- TypeScript
- YueScript
-- Assume the skill is interrupted and we need to stop the effect
effekNode:stop(laserHandle)
-- Assume the skill is interrupted and we need to stop the effect
effekNode:stop(laserHandle)
// Assume the skill is interrupted and we need to stop the effect
effekNode.stop(laserHandle);
-- Assume the skill is interrupted and we need to stop the effect
effekNode\stop laserHandle
3.4 Managing Multiple Effects
If multiple effects need to be played simultaneously, each effect's handle can be saved separately, and distinctions can be made in the callback.
- Lua
- Teal
- TypeScript
- YueScript
-- Play multiple effects
local handle1 = effekNode:play("Explosion.efk", Vec2(150, 250))
local handle2 = effekNode:play("Sparkle.efk", Vec2(200, 300))
-- Callback handling
effekNode:onEffekEnd(function(handle)
if handle == handle1 then
print("Explosion effect ended")
elseif handle == handle2 then
print("Sparkle effect ended")
end
end)
-- Play multiple effects
local handle1 = effekNode:play("Explosion.efk", Vec2(150, 250))
local handle2 = effekNode:play("Sparkle.efk", Vec2(200, 300))
-- Callback handling
effekNode:onEffekEnd(function(handle: integer)
if handle == handle1 then
print("Explosion effect ended")
elseif handle == handle2 then
print("Sparkle effect ended")
end
end)
// Play multiple effects
const handle1 = effekNode.play("Explosion.efk", Vec2(150, 250));
const handle2 = effekNode.play("Sparkle.efk", Vec2(200, 300));
// Callback handling
effekNode.onEffekEnd(handle => {
if (handle === handle1) {
print("Explosion effect ended");
} else if (handle === handle2) {
print("Sparkle effect ended");
}
});
-- Play multiple effects
handle1 = effekNode\play "Explosion.efk", Vec2 150, 250
handle2 = effekNode\play "Sparkle.efk", Vec2 200, 300
-- Callback handling
effekNode\onEffekEnd (handle) ->
if handle == handle1
print "Explosion effect ended"
elseif handle == handle2
print "Sparkle effect ended"
4. Using the Particle Class
Before the integration of Effekseer, Dora SSR provided the Particle
class for handling 2D particle effects.
However, the Particle
system has limited functionality, mainly relying on the CPU for calculations, resulting in inferior performance and effects compared to Effekseer. Therefore, unless you only wish to create relatively simple particle effects, the use of the Particle
class is not recommended.
4.1 Using the Particle Class
-
Creating a Particle Object
- Lua
- Teal
- TypeScript
- YueScript
local Particle <const> = require("Particle")
local particle = Particle("effect.par")local Particle <const> = require("Particle")
local particle = Particle("effect.par")import { Particle } from "Dora";
const particle = Particle("effect.par");_ENV = Dora
particle = Particle "effect.par"The
Particle
constructor takes one parameter:filename
: The path to the particle system definition file.
-
Starting and Stopping Particle Emission
- Lua
- Teal
- TypeScript
- YueScript
particle:start() -- Start emitting particles
particle:stop() -- Stop emitting particlesparticle:start() -- Start emitting particles
particle:stop() -- Stop emitting particlesparticle.start(); // Start emitting particles
particle.stop(); // Stop emitting particlesparticle\start! -- Start emitting particles
particle\stop! -- Stop emitting particles -
Listening for Particle System End Events
- Lua
- Teal
- TypeScript
- YueScript
particle:onFinished(function()
print("Particle system ended")
end)particle:onFinished(() => {
print("Particle system ended")
})particle.onFinished(() => {
print("Particle system ended");
});particle\onFinished () ->
print "Particle system ended"
4.2 Usage Example
- Lua
- Teal
- TypeScript
- YueScript
-- Import the Particle class
local Particle <const> = require("Particle")
-- Create a particle system object
local particle = Particle("effect.par")
-- Register the particle system end callback
particle:onFinished(function()
print("Particle system ended")
end)
-- Start emitting particles
particle:start()
-- Import the Particle class
local Particle <const> = require("Particle")
-- Create a particle system object
local particle = Particle("effect.par")
-- Register the particle system end callback
particle:onFinished(function()
print("Particle system ended")
end)
-- Start emitting particles
particle:start()
// Import the Particle class
import { Particle } from "Dora";
// Create a particle system object
const particle = Particle("effect.par");
// Register the particle system end callback
particle.onFinished(() => {
print("Particle system ended");
});
// Start emitting particles
particle.start();
-- Import the Particle class
_ENV = Dora
-- Create a particle system object
particle = Particle "effect.par"
-- Register the particle system end callback
particle\onFinished () ->
print "Particle system ended"
-- Start emitting particles
particle\start!
4.3 Customizing Particle Effects
Due to the limited functionality of the Particle
class, if you need to use it, you might need to modify the engine's particle system editor example (named "Particle"), which is built on the ImGui framework, to create your own particle editor to meet artistic production needs. The .par
files used in Dora SSR's particle system are essentially XML formatted text files, and you can refer to the editor code for how to generate and export them.
5. Conclusion
This article introduced how to use the Effekseer effect system in the Dora SSR engine. With the EffekNode
class, developers can easily load and control various complex effects in their games. We also mentioned the legacy Particle
class.
Effekseer provides powerful support for the creation and management of game effects, and it is generally recommended to use Effekseer for new projects to handle effects. We hope this tutorial helps you quickly get started with the effect system in Dora SSR and create stunning game effects.